import mx.utils.Delegate;

import gugga.animations.IAnimation;
import gugga.animations.PropertiesTweenAnimation;
import gugga.animations.PropertiesTweenAnimationType;
import gugga.debug.Assertion;
import gugga.events.EventDispatcher;
import gugga.tween.TweensManager;
import gugga.utils.EventRethrower;

/**
 * @author Stefan Yotov
 */
class gugga.animations.FilterTweenAnimation
	extends EventDispatcher implements IAnimation 
{
	private var mSubject : MovieClip;
	private var mFilterObjectType : Function;
	private var mTweenedFilterProperties : Array;
	private var mTweenToValues : Array;
	private var mTweenTime : Number;
	private var mEasingEquatation : Function;
	
	private var mFiltersArray : Array;
	private var mFilterInstance : Object;
	private var mFilterIndex : Number;
	
	private var mPropertiesTweenAnimation : PropertiesTweenAnimation;
	private var mTweenType : PropertiesTweenAnimationType;
	private var mTweensUpdatedDelegate : Function;
	
	public function FilterTweenAnimation()
	{
		super();
		
		mPropertiesTweenAnimation = new PropertiesTweenAnimation();
		
		EventRethrower.create(this, mPropertiesTweenAnimation, "completed");
		EventRethrower.create(this, mPropertiesTweenAnimation, "interrupted");
		EventRethrower.create(this, mPropertiesTweenAnimation, "start");
		
		mPropertiesTweenAnimation.addEventListener("completed", Delegate.create(this, onCompleted));
		
		mTweensUpdatedDelegate = Delegate.create(this, onTweensUpdated);
	}
	
	public function setFrameTween
	(
		aSubject : MovieClip, 
		aFilterObjectType : Function, 
		aTweenedFilterProperties : Array, 
		aTweenToValues : Array,
		aTweenTime : Number,
		aEasingEquation : Function
	) : Void
	{
		mSubject = aSubject;
		mFilterObjectType = aFilterObjectType;
		mTweenedFilterProperties = aTweenedFilterProperties;
		mTweenToValues = aTweenToValues;
		mTweenTime = aTweenTime;
		mEasingEquatation = aEasingEquation;
		
		mTweenType = PropertiesTweenAnimationType.FrameTween;
	}
	
	public function setTimeTween
	(
		aSubject : MovieClip, 
		aFilterObjectType : Function, 
		aTweenedFilterProperties : Array, 
		aTweenToValues : Array,
		aTweenTime : Number, 
		aEasingEquation : Function
	) : Void
	{
		mSubject = aSubject;
		mFilterObjectType = aFilterObjectType;
		mTweenedFilterProperties = aTweenedFilterProperties;
		mTweenToValues = aTweenToValues;
		mTweenTime = aTweenTime;
		mEasingEquatation = aEasingEquation;
		
		mTweenType = PropertiesTweenAnimationType.TimeTween;
	}
	
	public function addCuePoint(aPosition : Number, aEventName : String) : Void 
	{
		mPropertiesTweenAnimation.addCuePoint(aPosition, aEventName);
		EventRethrower.create(this, mPropertiesTweenAnimation, aEventName);
	}

	public function start() : Void 
	{
		mFiltersArray = mSubject.filters;
		if(!mFiltersArray)
		{
			mFiltersArray = new Array();
		}
		
		for (var i : Number = 0; i < mFiltersArray.length; i++) 
		{
			if(mFiltersArray[i] instanceof mFilterObjectType)
			{
				Assertion.warningIfTrue(
					(mFilterInstance != null),
					"Subject's filters array contains multiple instances of the tweened filter type.", 
					this, arguments);
					
				mFilterInstance = mFiltersArray[i]; 
				mFilterIndex = i;
			}
		}
		
		if(!mFilterInstance)
		{
			mFilterInstance = new mFilterObjectType();
			mFilterIndex = 0;
			mFiltersArray.push(mFilterInstance);
		}
		
		if(mTweenType == PropertiesTweenAnimationType.FrameTween)
		{
			mPropertiesTweenAnimation.setFrameTween(
				mFilterInstance, mTweenedFilterProperties, mTweenToValues, mTweenTime, mEasingEquatation);
		}
		else
		{
			mPropertiesTweenAnimation.setTimeTween(
				mFilterInstance, mTweenedFilterProperties, mTweenToValues, mTweenTime, mEasingEquatation);
		}
		
		TweensManager.Instance.addEventListener("tweensUpdated", mTweensUpdatedDelegate);
		
		mPropertiesTweenAnimation.start();
	}

	public function isRunning() : Boolean 
	{
		return mPropertiesTweenAnimation.isRunning();
	}

	public function isImmediatelyInterruptable() : Boolean 
	{
		return mPropertiesTweenAnimation.isImmediatelyInterruptable();
	}

	public function interrupt() : Void 
	{
		TweensManager.Instance.removeEventListener("tweensUpdated", mTweensUpdatedDelegate);
		mPropertiesTweenAnimation.interrupt();
		mFilterInstance = null;
		mFiltersArray = null;
	}
	
	private function onTweensUpdated () : Void
	{
		mFiltersArray[mFilterIndex] = mFilterInstance;
		mSubject.filters = mFiltersArray;
	}
	
	private function onCompleted () : Void
	{
		TweensManager.Instance.removeEventListener("tweensUpdated", mTweensUpdatedDelegate);
		mFilterInstance = null;
		mFiltersArray = null;
	}
}